home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / Edit.p < prev    next >
Encoding:
Text File  |  1995-10-27  |  55.1 KB  |  2,069 lines  |  [TEXT/PJMM]

  1. unit Edit;
  2.  
  3. {Editing routines used by NIH Image}
  4.  
  5. interface
  6.  
  7.     uses
  8.         Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils,Resources, Errors, Palettes, globals, Utilities, Graphics, Camera, analysis, file1, filters, stacks, Lut, Text, math;
  9.  
  10.  
  11.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  12.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  13.     procedure Rotate (DoWhat: FlipRotateType);
  14.     procedure DoCopy;
  15.     procedure DoCut;
  16.     procedure DoPaste;
  17.     procedure DoClear;
  18.     procedure ShowClipboard;
  19.     procedure DoObject (obj: ObjectType; event: EventRecord);
  20.     procedure DoSprayCan;
  21.     procedure DoBrush (event: EventRecord);
  22.     procedure DoText (loc: point);
  23.     procedure SetSprayCanSize;
  24.     procedure SetBrushSize;
  25.     procedure SetLineWidth;
  26.     procedure UpdateEditMenu;
  27.     procedure ConverToSystemClipboard;
  28.     procedure ZoomOut;
  29.     procedure ZoomIn (event: EventRecord);
  30.     procedure Scroll (event: EventRecord);
  31.     procedure DoFill (event: EventRecord);
  32.     procedure DoGrow (WhichWindow: WindowPtr; event: EventRecord);
  33.     procedure DrawCharacter (ch: char);
  34.     procedure ConvertFromSystemClipboard;
  35.     procedure SetupOperation (item: integer);
  36.     procedure PastePicture;
  37.     procedure DoUndo;
  38.     procedure FindWhatToCopy;
  39.     procedure CopyResults;
  40.  
  41.  
  42. implementation
  43.  
  44.  
  45.     procedure PivotSelection (var SelectionRect: rect; WindowRect: rect);
  46.         var
  47.             OldWidth, NewWidth, OldHeight, NewHeight, hCenter, vCenter, NewLeft, NewTop: integer;
  48.     begin
  49.         with SelectionRect do begin
  50.                 OldWidth := right - left;
  51.                 OldHeight := bottom - top;
  52.                 hCenter := left + OldWidth div 2;
  53.                 vCenter := top + OldHeight div 2;
  54.             end;
  55.         NewWidth := OldHeight;
  56.         NewHeight := OldWidth;
  57.         NewLeft := hCenter - NewWidth div 2;
  58.         NewTop := vCenter - NewHeight div 2;
  59.         with WindowRect do begin
  60.                 if (NewLeft + NewWidth) > right then
  61.                     NewLeft := right - NewWidth;
  62.                 if (NewTop + NewHeight) > bottom then
  63.                     NewTop := bottom - NewHeight;
  64.                 if NewLeft < 0 then
  65.                     NewLeft := 0;
  66.                 if NewTop < 0 then
  67.                     NewTop := 0;
  68.             end;
  69.         with SelectionRect do begin
  70.                 left := NewLeft;
  71.                 top := NewTop;
  72.                 right := NewLeft + NewWidth;
  73.                 bottom := NewTop + NewHeight;
  74.             end;
  75.     end;
  76.  
  77.  
  78.     procedure FlipLine (var LineBuf: LineType; width: integer);
  79.         var
  80.             TempLine: LineType;
  81.             i, WidthLessOne: integer;
  82.     begin
  83.         TempLine := LineBuf;
  84.         WidthLessOne := width - 1;
  85.         for i := 0 to width - 1 do
  86.             LineBuf[i] := TempLine[WidthLessOne - i];
  87.     end;
  88.  
  89.  
  90.     procedure ScreenToOffscreenRect (var r: rect);
  91.         var
  92.             p1, p2: point;
  93.     begin
  94.         with r do begin
  95.                 p1.h := left;
  96.                 p1.v := top;
  97.                 p2.h := right;
  98.                 p2.v := bottom;
  99.                 ScreenToOffscreen(p1);
  100.                 ScreenToOffscreen(p2);
  101.                 Pt2Rect(p1, p2, r);
  102.             end;
  103.     end;
  104.  
  105.  
  106.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  107.         var
  108.             SaveInfo: InfoPtr;
  109.             width, height, hDst, vSrc, vDst, hSrc, i, inc: integer;
  110.             LineBuf: LineType;
  111.             srect, drect, MaskRect: rect;
  112.             AutoSelectAll: boolean;
  113.             SaveRow:integer;
  114.             NextUpdate: LongInt;
  115.  
  116.     begin
  117.         if NotRectangular or NotInBounds or NoUndo then
  118.             exit(FlipOrRotate);
  119.         AutoSelectAll := not Info^.RoiShowing;
  120.         if AutoSelectAll then
  121.             SelectAll(true);
  122.         if TooWide then
  123.             exit(FlipOrRotate);
  124.         ShowWatch;
  125.         SetupUndoFromClip;
  126.         SetupUndo;
  127.         if (DoWhat = RotateLeft) or (DoWhat = RotateRight) then
  128.             WhatToUndo := UndoRotate
  129.         else
  130.             WhatToUndo := UndoFlip;
  131.         SetupUndoInfoRec;
  132.         SaveInfo := Info;
  133.         srect := info^.RoiRect;
  134.         case DoWhat of
  135.  
  136.             RotateLeft, RotateRight: 
  137.                 with srect do begin
  138.                         if OptionKeyWasDown then
  139.                             DoOperation(EraseOp);
  140.                         drect := srect;
  141.                         with info^ do begin
  142.                                 PivotSelection(drect, PicRect);
  143.                                 MaskRect := drect;
  144.                                 RoiRect := drect;
  145.                                 RectRgn(roiRgn, RoiRect);
  146.                             end;
  147.                         width := right - left;
  148.                         if DoWhat = RotateLeft then begin
  149.                                 hDst := drect.left;
  150.                                 inc := 1
  151.                             end
  152.                         else begin
  153.                                 hDst := drect.right - 1;
  154.                                 inc := -1
  155.                             end;
  156.                         SaveRow:=top;
  157.                         NextUpdate:=TickCount+6; {10/sec}
  158.                         for vSrc := top to bottom - 1 do begin
  159.                                 Info := UndoInfo;
  160.                                 GetLine(left, vSrc, width, LineBuf);
  161.                                 if DoWhat = RotateLeft then
  162.                                     FlipLine(LineBuf, width);
  163.                                 Info := SaveInfo;
  164.                                 PutColumn(hDst, drect.top, width, LineBuf);
  165.                                 hDst := hDst + inc;
  166.                                 if TickCount>=NextUpdate then begin
  167.                                     SetRect(MaskRect, left, SaveRow, left+width, vSrc + 1);
  168.                                     UpdateScreen(MaskRect);
  169.                                     SaveRow:=vSrc+1;
  170.                                     NextUpdate:=TickCount+6;
  171.                                     ShowAnimatedWatch;
  172.                                 end;
  173.                             end;
  174.                             SetRect(MaskRect, left, SaveRow, left+width, bottom);
  175.                             UpdateScreen(MaskRect);
  176.                     end;
  177.  
  178.             FlipVertical: 
  179.                 with srect do begin
  180.                         width := right - left;
  181.                         vDst := bottom;
  182.                         for vSrc := top to bottom - 1 do begin
  183.                                 Info := UndoInfo;
  184.                                 GetLine(left, vSrc, width, LineBuf);
  185.                                 Info := SaveInfo;
  186.                                 vDst := vDst - 1;
  187.                                 PutLine(left, vDst, width, LineBuf);
  188.                             end;
  189.                     end;
  190.  
  191.             FlipHorizontal: 
  192.                 with srect do begin
  193.                         width := right - left;
  194.                         SaveRow:=top;
  195.                         NextUpdate:=TickCount+6; {10/sec}
  196.                         for vSrc := top to bottom - 1 do begin
  197.                                 Info := UndoInfo;
  198.                                 GetLine(left, vSrc, width, LineBuf);
  199.                                 FlipLine(LineBuf, width);
  200.                                 Info := SaveInfo;
  201.                                 PutLine(left, vSrc, width, LineBuf);
  202.                                 if TickCount>=NextUpdate then begin
  203.                                     SetRect(MaskRect, left, SaveRow, left+width, vSrc + 1);
  204.                                     UpdateScreen(MaskRect);
  205.                                     SaveRow:=vSrc+1;
  206.                                     NextUpdate:=TickCount+6;
  207.                                     ShowAnimatedWatch;
  208.                                 end;
  209.                             end;
  210.                             SetRect(MaskRect, left, SaveRow, left+width, bottom);
  211.                             UpdateScreen(MaskRect);
  212.                     end;
  213.  
  214.         end; {case}
  215.         Info := SaveInfo;
  216.         Info^.changes := true;
  217.         SetupRoiRect;
  218.         if AutoSelectAll then
  219.             KillRoi;
  220.     end;
  221.  
  222.  
  223.  
  224.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  225.         var
  226.             SrcInfo, DstInfo: InfoPtr;
  227.             Srcwidth, DstWidth, DstHeight, hDst, vSrc, vDst, hSrc, i, inc, ignore: integer;
  228.             LineBuf: LineType;
  229.             SourceRect, DstRect, MaskRect: rect;
  230.             AutoSelectAll, isStack: boolean;
  231.             SaveCol:integer;
  232.             NextUpdate: LongInt;
  233.     begin
  234.         if NotRectangular or NotInBounds then
  235.             exit(RotateToNewWindow);
  236.         AutoSelectAll := not Info^.RoiShowing;
  237.         isStack := info^.StackInfo <> nil;
  238.         if AutoSelectAll then
  239.             SelectAll(true);
  240.         if TooWide then
  241.             exit(RotateToNewWindow);
  242.         ShowWatch;
  243.         SrcInfo := info;
  244.         with info^, info^.RoiRect do begin
  245.                 SourceRect := RoiRect;
  246.                 SrcWidth := right - left;
  247.                 DstWidth := bottom - top;
  248.                 DstHeight := right - left;
  249.                 if not NewPicWindow(title, DstWidth, DstHeight) then begin
  250.                         KillRoi;
  251.                         AbortMacro;
  252.                         exit(RotateToNewWindow)
  253.                     end;
  254.                 DstInfo := info;
  255.                 DstRect := info^.PicRect;
  256.             end;
  257.         if DoWhat = RotateLeft then begin
  258.                 hDst := 0;
  259.                 inc := 1
  260.             end
  261.         else begin
  262.                 hDst := DstWidth - 1;
  263.                 inc := -1
  264.             end;
  265.         with SourceRect do begin
  266.             SaveCol:=hDst;
  267.             NextUpdate:=TickCount+6; {10/sec}
  268.             for vSrc := top to bottom - 1 do begin
  269.                     Info := SrcInfo;
  270.                     GetLine(left, vSrc, SrcWidth, LineBuf);
  271.                     if DoWhat = RotateLeft then
  272.                         FlipLine(LineBuf, SrcWidth);
  273.                     Info := DstInfo;
  274.                     PutColumn(hDst, 0, SrcWidth, LineBuf);
  275.                     if TickCount>=NextUpdate then begin
  276.                         if DoWhat=RotateLeft
  277.                             then SetRect(MaskRect, SaveCol, 0, hDst+1, SrcWidth)
  278.                             else SetRect(MaskRect, hDst, 0, SaveCol+1, SrcWidth);
  279.                         UpdateScreen(MaskRect);
  280.                         SaveCol:=hDst+1;
  281.                         NextUpdate:=TickCount+6;
  282.                         ShowAnimatedWatch;
  283.                     end;
  284.                     hDst := hDst + inc;
  285.                 end; {for}
  286.                 if DoWhat=RotateLeft
  287.                     then SetRect(MaskRect, SaveCol, 0, dstWidth, SrcWidth)
  288.                     else SetRect(MaskRect, 0, 0, SaveCol+1, SrcWidth);
  289.                 UpdateScreen(MaskRect);
  290.             end; {with}
  291.         info^.changes := true;
  292.         if AutoSelectAll and not isStack then
  293.             with SrcInfo^ do begin
  294.                     Changes := false;
  295.                     ignore := CloseAWindow(wptr);
  296.                     info := DstInfo;
  297.                 end;
  298.     end;
  299.  
  300.  
  301.     procedure Rotate; {(DoWhat: FlipRotateType)}
  302.         const
  303.             NewWindowID = 3;
  304.         var
  305.             mylog: DialogPtr;
  306.             item: integer;
  307.             NewWindow: boolean;
  308.     begin
  309.         with info^, info^.RoiRect do
  310.             if RoiShowing then
  311.                 NewWindow := ((right - left) > PicRect.bottom) or ((bottom - top) > PicRect.right)
  312.             else begin
  313.                     RotateToNewWindow(DoWhat);
  314.                     exit(Rotate);
  315.                 end;
  316.         InitCursor;
  317.         mylog := GetNewDialog(120, nil, pointer(-1));
  318.         SetDlogItem(mylog, NewWindowID, ord(NewWindow));
  319.         OutlineButton(MyLog, ok, 16);
  320.         repeat
  321.             if item = NewWindowID then begin
  322.                     NewWindow := not NewWindow;
  323.                     SetDlogItem(mylog, NewWindowID, ord(NewWindow));
  324.                 end;
  325.             ModalDialog(nil, item);
  326.         until (item = ok) or (item = cancel);
  327.         DisposeDialog(mylog);
  328.         if item = cancel then
  329.             exit(Rotate);
  330.         if NewWindow then
  331.             RotateToNewWindow(DoWhat)
  332.         else
  333.             FlipOrRotate(DoWhat);
  334.     end;
  335.  
  336.  
  337.     function CopyImage: boolean;
  338.         var
  339.             err, width, EvenWidth, height, size: LongInt;
  340.             line: integer;
  341.             ClipXOffset, ClipYOffset: integer;
  342.             SavePort: GrafPtr;
  343.             SaveGDevice: GDHandle;
  344.     begin
  345.         if OpPending then begin
  346.             KillRoi;
  347.             RestoreRoi;
  348.         end;
  349.         with info^, info^.RoiRect do begin
  350.             if (RoiType = RectRoi) and (PictureType = FrameGrabberType) then begin
  351.                 {We can't offset an roi copied from Camera window or "live" paste won't work}
  352.                 ClipXOffset := 0;
  353.                 ClipYOffset := 0;
  354.                 width := picRect.right;
  355.                 height := picRect.bottom;
  356.             end else begin
  357.                 ClipXOffset := left;
  358.                 ClipYOffset := top;
  359.                 width := right - left;
  360.                 height := bottom - top;
  361.             end;
  362.             if odd(width) then
  363.                 EvenWidth := width + 1
  364.             else
  365.                 EvenWidth := width;
  366.             size := EvenWidth * height;
  367.             if size > ClipBufSize then begin
  368.                 PutError(StringOf('This ',size div 1024:1,'K selection is larger than the ',ClipBufSize div 1024:1,'K Clipboard buffer.'));
  369.                 WhatsOnClip := NothingOnClip;
  370.                 AbortMacro;
  371.                 CopyImage := false;
  372.                 exit(CopyImage)
  373.             end;
  374.         end;
  375.         with ClipBufInfo^ do begin
  376.             PixelsPerLine := width;
  377.             BytesPerRow := EvenWidth;
  378.             nLines := height;
  379.             RoiRect := info^.RoiRect;
  380.             OffsetRect(RoiRect, -ClipXOffset, -ClipYOffset);
  381.             roiType := Info^.roiType;
  382.             PicRect := RoiRect;
  383.             with osPort^.portPixMap^^ do begin
  384.                     RowBytes := BitOr(BytesPerRow, $8000);
  385.                     bounds := PicRect;
  386.                 end;
  387.             with osPort^ do begin
  388.                     PortRect := PicRect;
  389.                     RectRgn(visRgn, PicRect);
  390.                 end;
  391.             if RoiType = RectRoi then begin
  392.                 if info^.PictureType = FrameGrabberType then
  393.                     WhatsOnClip := CameraPic
  394.                 else
  395.                     WhatsOnClip := RectPic
  396.             end else
  397.                 WhatsOnClip := NonRectPic;
  398.             SaveGDevice := GetGDevice;
  399.             SetGDevice(osGDevice);
  400.             GetPort(SavePort);
  401.             SetPort(GrafPtr(osPort));
  402.             CopyRgn(info^.roiRgn, roiRgn);
  403.             OffsetRgn(roiRgn, -ClipXOffset, -ClipYOffset);
  404.             ctable := info^.ctable;
  405.             pmForeColor(BlackIndex);
  406.             pmBackColor(WhiteIndex);
  407.             CopyBits(BitMapHandle(Info^.osPort^.portPixMap)^^, BitMapHandle(osPort^.PortPixMap)^^, Info^.RoiRect, RoiRect, SrcCopy, nil);
  408.             pmForeColor(ForegroundIndex);
  409.             pmBackColor(BackgroundIndex);
  410.             SetPort(SavePort);
  411.             SetGDevice(SaveGDevice);
  412.         end; {with}
  413.         CopyImage := true;
  414.     end;
  415.  
  416.  
  417.     procedure CopyWindow;
  418.         var
  419.             tPort: GrafPtr;
  420.             WindowSize: LongInt;
  421.             WindowRect: rect;
  422.             WhichWindow: WindowPtr;
  423.             kind, ignore: integer;
  424.             HidingPasteControl: boolean;
  425.             SaveGDevice: GDHandle;i:integer;
  426.     begin
  427.         WhichWindow := FrontWindow;
  428.         if WhichWindow = nil then
  429.             exit(CopyWindow);
  430.         WindowRect := WhichWindow^.PortRect;
  431.         kind := WindowPeek(WhichWindow)^.WindowKind;
  432.         HidingPasteControl := false;
  433.         with WindowRect do begin
  434.                 WindowSize := right;
  435.                 WindowSize := WindowSize * bottom;
  436.             end;
  437.         if kind = LUTKind then
  438.             WindowRect.bottom := 256;
  439.         case kind of
  440.             ProfilePlotKind:  begin
  441.                     ConvertPlotToText;
  442.                     ClipTextInBuffer := true;
  443.                 end;
  444.             CalibrationPlotKind:  begin
  445.                     ConvertCalibrationCurveToText;
  446.                     ClipTextInBuffer := true;
  447.                 end;
  448.             HistoKind, LUTKind, MapKind, ToolKind:  begin
  449.                     if PasteControl <> nil then begin
  450.                             ignore := CloseAWindow(PasteControl);
  451.                             HidingPasteControl := true;
  452.                         end;
  453.                     case kind of
  454.                         HistoKind:  begin
  455.                                 ConvertHistoToText;
  456.                                 ClipTextInBuffer := true;
  457.                                 DrawHistogram;
  458.                             end;
  459.                         MapKind: 
  460.                             DrawMap;
  461.                         LUTKind: 
  462.                             DrawLUT;
  463.                         ToolKind: 
  464.                             DrawTools;
  465.                     end; {case}
  466.                 end;
  467.             otherwise
  468.         end; {case}
  469.         if NoUndo then begin
  470.                 WhatsOnClip := NothingOnClip;
  471.                 exit(CopyWindow)
  472.             end;
  473.         ClipboardConverted := false;
  474.         with ClipBufInfo^ do begin
  475.                 RoiType := RectRoi;
  476.                 RoiRect := WindowRect;
  477.                 RectRgn(roiRgn, RoiRect);
  478.                 PicRect := WindowRect;
  479.                 PixelsPerLine := WindowRect.right;
  480.                 BytesPerRow := PixelsPerLine;
  481.                 if odd(BytesPerRow) then
  482.                     BytesPerRow := BytesPerRow + 1;
  483.                 nLines := WindowRect.bottom;
  484.                 with osPort^.portPixMap^^ do begin
  485.                         RowBytes := BitOr(BytesPerRow, $8000);
  486.                         bounds := WindowRect;
  487.                     end;
  488.                 with osPort^ do begin
  489.                         PortRect := PicRect;
  490.                         RectRgn(visRgn, PicRect);
  491.                         SetRectRgn(ClipRgn, 0, 0, 30000, 30000);
  492.                     end;
  493.                 WhatsOnClip := RectPic;
  494.                 SaveGDevice := GetGDevice;
  495.                 SetGDevice(osGDevice);
  496.                 GetPort(tPort);
  497.                 SetPort(GrafPtr(osPort));
  498.                 RGBForeColor(BlackRGB);
  499.                 RGBBackColor(WhiteRGB);
  500.                 if (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) then begin
  501.                         EraseRect(osPort^.portRect);
  502.                         DrawPlot
  503.                     end
  504.                 else
  505.                     CopyBits(WhichWindow^.PortBits, BitMapHandle(osPort^.portPixMap)^^, WindowRect, WindowRect, SrcCopy, nil);
  506.                 SetPort(tPort);
  507.                 SetGDevice(SaveGDevice);
  508.             end; {with}
  509.         if HidingPasteControl then
  510.             ShowPasteControl;
  511.     end;
  512.  
  513.  
  514.     procedure CopyResults;
  515.         var
  516.             err: OSErr;
  517.     begin
  518.         CopyResultsToBuffer(1, mCount, ShowHeadings);
  519.         UnsavedResults := false;
  520.         err := ZeroScrap;
  521.         if err = NoErr then begin
  522.                 err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  523.                 WhatsOnClip := NothingOnClip; {The text is on the System Scrap}
  524.             end;
  525.     end;
  526.  
  527.  
  528.     procedure DoCopy;
  529.         var
  530.             err: OSErr;
  531.     begin
  532.         err := ZeroScrap;
  533.         OldScrapCount := GetScrapCount;
  534.         case WhatToCopy of
  535.             CopyColor: 
  536.                 DoCopyColor;
  537.             CopySelection:  begin
  538.                     if not CopyImage then exit(DoCopy);
  539.                     ClipTextInBuffer := false;
  540.                     ClipboardConverted := false;
  541.                 end;
  542.             CopyHistogram, CopyPlot, CopyCalibrationPlot, CopyCLUT, CopyGrayMap, CopyTools: 
  543.                 CopyWindow;
  544.             CopyMeasurements: 
  545.                 CopyResults;
  546.             CopyText: 
  547.                 DoTextCopy;
  548.             otherwise
  549.                 beep;
  550.         end;
  551.     end;
  552.  
  553.  
  554.     procedure DoCut;
  555.     begin
  556.         DoCopy;
  557.         DoClear;
  558.     end;
  559.  
  560.  
  561.     procedure CenterRect (inRect, outRect: rect; var ResultRect: rect);
  562. {Creates a new rectangle(ResultsRect) that is the same size as inRect, but centered within outRect.}
  563.         var
  564.             width, height, hcenter, vcenter: integer;
  565.     begin
  566.         with inRect do begin
  567.                 width := right - left;
  568.                 height := bottom - top;
  569.             end;
  570.         with outRect do begin
  571.                 hcenter := left + (right - left) div 2;
  572.                 vcenter := top + (bottom - top) div 2;
  573.             end;
  574.         with ResultRect do begin
  575.                 left := hcenter - width div 2;
  576.                 top := vcenter - height div 2;
  577.                 right := left + width;
  578.                 bottom := top + height;
  579.             end;
  580.     end;
  581.  
  582.  
  583.     procedure PastePicture;
  584.         var
  585.             loc: point;
  586.             SrcWidth, SrcHeight, DstHeight, DstWidth, dh, dv: integer;
  587.             DestRect: rect;
  588.             WindowNotResized: boolean;
  589.     begin
  590.         if LivePasteMode or (PasteTransferMode <> SrcCopy) then begin
  591.                 LivePasteMode := false;
  592.                 PasteTransferMode := SrcCopy;
  593.                 if PasteControl <> nil then
  594.                     DrawPasteControl
  595.             end;
  596.         with info^ do begin
  597.                 SetupUndo;
  598.                 WhatToUndo := UndoPaste;
  599.                 if RoiShowing then
  600.                     with RoiRect do {Pasting back into selection of same size?}
  601.                         if ((right - left) = (ClipBufInfo^.RoiRect.right - ClipBufInfo^.RoiRect.left)) and ((bottom - top) = (ClipBufInfo^.RoiRect.bottom - ClipBufInfo^.RoiRect.top)) and (ClipBufInfo^.RoiType = RoiType) then begin
  602.                                 OpPending := true;
  603.                                 CurrentOp := PasteOp;
  604.                                 exit(PastePicture)
  605.                             end;
  606.                 with ClipBufInfo^.RoiRect do {Pasting into same size window?}
  607.                     if (PicRect.right = right - left) and (PicRect.bottom = (bottom - top)) and (ClipBufInfo^.RoiType = RectRoi) then begin
  608.                             SelectAll(true);
  609.                             WhatToUndo := UndoPaste;
  610.                             OpPending := true;
  611.                             CurrentOp := PasteOp;
  612.                             exit(PastePicture)
  613.                         end;
  614.                 if RoiShowing or (roiType <> NoRoi) then
  615.                     KillRoi;
  616.                 with ClipBufInfo^.RoiRect do begin
  617.                         SrcWidth := right - left;
  618.                         SrcHeight := bottom - top;
  619.                     end;
  620.                 with SrcRect do begin
  621.                         DstWidth := right - left;
  622.                         DstHeight := bottom - top;
  623.                     end;
  624.                 with initwrect do
  625.                     WindowNotResized := (DstWidth = (right - left)) and (DstHeight = (bottom - top));
  626.                 if ((SrcWidth > DstWidth) or (SrcHeight > DstHeight)) and WindowNotResized then
  627.                     DestRect := PicRect
  628.                 else
  629.                     DestRect := SrcRect;
  630.                 CenterRect(ClipBufInfo^.RoiRect, DestRect, RoiRect);
  631.                 roiType := ClipBufInfo^.roiType;
  632.                 CopyRgn(ClipBufInfo^.roiRgn, roiRgn);
  633.                 dh := RoiRect.left - roiRgn^^.rgnbbox.left;
  634.                 dv := RoiRect.top - roiRgn^^.rgnbbox.top;
  635.                 OffsetRgn(roiRgn, dh, dv);
  636.                 RoiShowing := true;
  637.                 OpPending := true;
  638.                 CurrentOp := PasteOp;
  639.                 BinaryPic := false;
  640.             end;{with}
  641.     end;
  642.  
  643.  
  644.     procedure ConvertFromSystemClipboard;
  645.   {Converts system-wide clipboard to local clipboard.}
  646.     var
  647.         phandle: handle;
  648.         offset, length, size, EvenWidth: LongInt;
  649.         pframe: rect;
  650.         width, height: LongInt;
  651.         tPort: GrafPtr;
  652.         ScrapInfo: PScrapStuff;
  653.         SaveGDevice: GDHandle;
  654.     begin
  655.         ScrapInfo := InfoScrap;
  656.         if ScrapInfo^.ScrapSize <= 0 then
  657.             exit(ConvertFromSystemClipboard);
  658.         phandle := NewHandle(0);
  659.         length := GetScrap(phandle, 'PICT', offset);
  660.         if length > 0 then begin
  661.             ShowWatch;
  662.             pframe := PicHandle(phandle)^^.PicFrame;
  663.             with pframe do begin
  664.                 width := right - left;
  665.                 if odd(width) then
  666.                     EvenWidth := width + 1
  667.                 else
  668.                     EvenWidth := width;
  669.                 height := bottom - top;
  670.                 size := EvenWidth * height;
  671.                 if size > ClipBufSize then begin
  672.                     PutError(StringOf('The ', size div 1024:1,'K image on the system clipboard is too large to paste.'));
  673.                     DisposeHandle(phandle);
  674.                     exit(ConvertFromSystemClipboard)
  675.                 end;
  676.             end;
  677.             with ClipBufInfo^ do begin
  678.                 PixelsPerLine := width;
  679.                 nlines := height;
  680.                 SetRect(PicRect, 0, 0, width, height);
  681.                 RoiRect := PicRect;
  682.                 RoiType := RectRoi;
  683.                 SaveGDevice := GetGDevice;
  684.                 SetGDevice(osGDevice);
  685.                 GetPort(tPort);
  686.                 SetPort(GrafPtr(osPort));
  687.                 RectRgn(roiRgn, RoiRect);
  688.                 BytesPerRow := EvenWidth;
  689.                 with osPort^.portPixMap^^ do begin
  690.                     RowBytes := BitOr(BytesPerRow, $8000);
  691.                     bounds := PicRect;
  692.                 end;
  693.                 with CGrafPtr(osPort)^ do begin
  694.                     PortRect := PicRect;
  695.                     RectRgn(visRgn, PicRect);
  696.                     SetRectRgn(ClipRgn, 0, 0, 30000, 30000);
  697.                 end;
  698.                 RGBForecolor(WhiteRGB);
  699.                 PaintRect(PicRect);
  700.                 DrawPicture(PicHandle(phandle), PicRect);
  701.                 SetPort(tPort);
  702.                 SetGDevice(SaveGDevice);
  703.             end; {with}
  704.             WhatsOnClip := ImportedPic;
  705.         end else begin
  706.             length := GetScrap(phandle, 'TEXT', offset);
  707.             if (length > 0) and (length < MaxTextBufSize) then begin
  708.                 BlockMove(phandle^, ptr(TextBufP), length);
  709.                 TextBufSize := length;
  710.                 WhatsOnClip := TextOnClip;
  711.             end;
  712.         end;
  713.         DisposeHandle(phandle);
  714.     end;
  715.  
  716.  
  717.     procedure PasteText;
  718.         var
  719.             nTextLines, LineWidth, MaxLineWidth, MaxRectWidth, MaxRectHeight: integer;
  720.             LineStart, LineEnd, height, kind: integer;
  721.             fwptr: WindowPtr;
  722.             SaveGDevice: GDHandle;
  723.             okay: boolean;
  724.     begin
  725.         fwptr := FrontWindow;
  726.         if fwptr = nil then
  727.             exit(PasteText);
  728.         kind := WindowPeek(fwptr)^.WindowKind;
  729.         if Kind = TextKind then begin
  730.             DoTextPaste;
  731.             exit(PasteText);
  732.         end;
  733.         if TextBufSize > 5000 then begin
  734.             PutError('The maximum number of characters that can be pasted is 5000.');
  735.             exit(PasteText);
  736.         end;
  737.         if (Info = NoInfo) or NoUndo then
  738.             exit(PasteText);
  739.         with ClipBufInfo^ do begin
  740.             SaveGDevice := GetGDevice;
  741.             SetGDevice(osGDevice);
  742.             SetPort(GrafPtr(osPort));
  743.             RGBForeColor(BlackRGB);
  744.             RGBBackColor(WhiteRGB);
  745.             TextFont(CurrentFontID);
  746.             TextFace(CurrentStyle);
  747.             TextSize(CurrentSize);
  748.         end;
  749.         with info^ do if (not RoiShowing) or (RoiShowing and (RoiType <> RectRoi)) then begin
  750.             KillRoi;
  751.             nTextLines := 1;
  752.             MaxLineWidth := 10;
  753.             LineStart := 1;
  754.             LineEnd := 0;
  755.             repeat
  756.                 LineEnd := LineEnd + 1;
  757.                 if TextBufP^[LineEnd] = cr then begin
  758.                         nTextLines := nTextLines + 1;
  759.                         LineWidth := TextWidth(ptr(TextBufP), LineStart - 1, LineEnd - LineStart);
  760.                         if LineWidth > MaxLineWidth then
  761.                             MaxLineWidth := LineWidth;
  762.                         LineStart := LineEnd;
  763.                     end;
  764.             until LineEnd >= TextBufSize;
  765.             if LineEnd > LineStart then begin
  766.                     LineWidth := TextWidth(ptr(TextBufP), LineStart - 1, LineEnd - LineStart);
  767.                     if LineWidth > MaxLineWidth then
  768.                         MaxLineWidth := LineWidth;
  769.                 end;
  770.             height := nTextLines * CurrentSize + CurrentSize div 4;
  771.             MaxRectHeight := (PicRect.bottom * 2) div 3;
  772.             if height > MaxRectHeight then
  773.                 height := MaxRectHeight;
  774.             MaxLineWidth := MaxLineWidth + CurrentSize div 2;
  775.             MaxRectWidth := (PicRect.right * 2) div 3;
  776.             if MaxLineWidth > MaxRectWidth then begin
  777.                     MaxLineWidth := MaxRectWidth;
  778.                     height := MaxRectHeight;
  779.                 end;
  780.             with RoiRect do begin
  781.                     left := 0;
  782.                     top := 0;
  783.                     right := MaxLineWidth;
  784.                     bottom := height;
  785.                 end;
  786.             RoiType := RectRoi;
  787.             MakeRegion;
  788.         end;
  789.         okay := CopyImage;
  790.         if okay then begin
  791.             WhatsOnClip := TextOnClip;
  792.             SetRectRgn(ClipBufInfo^.osPort^.ClipRgn, 0, 0, 30000, 30000);  {Why is this needed?}
  793.             TETextBox(ptr(TextBufP), TextBufSize, ClipBufInfo^.RoiRect, TextJust);
  794.             PastePicture;
  795.         end;
  796.         SetGDevice(SaveGDevice);
  797.     end;
  798.  
  799.  
  800.     procedure DoPaste;
  801.         var
  802.             NewScrapCount: integer;
  803.     begin
  804.         if ((info = NoInfo) and (WhatsOnClip in [RectPic, NonRectPic, ImportedPic, CameraPic])) then begin
  805.                 if CurrentWindow <> TextKind then begin
  806.                         PutError('You must have an image window open to paste.');
  807.                         exit(DoPaste);
  808.                     end
  809.                 else
  810.                     WhatsOnClip := NothingOnClip;
  811.             end;
  812.         RoiUpdateTime := 0;
  813.         NewScrapCount := GetScrapCount;
  814.         if NewScrapCount <> OldScrapCount then begin
  815.                 WhatsOnClip := NothingOnClip;
  816.                 OldScrapCount := NewScrapCount;
  817.             end;
  818.         case WhatsOnClip of
  819.             aColor: 
  820.                 PasteColor;
  821.             RectPic, NonRectPic, ImportedPic, CameraPic: 
  822.                 PastePicture;
  823.             TextOnClip: 
  824.                 PasteText;
  825.             LivePic: 
  826.                 WhatsOnClip := NothingOnClip;
  827.             NothingOnClip:  begin
  828.                     ConvertFromSystemClipboard;
  829.                     if (WhatsOnClip = ImportedPic) and (info <> NoInfo) then
  830.                         PastePicture
  831.                     else if WhatsOnClip = textOnClip then
  832.                         PasteText
  833.                     else
  834.                         beep;
  835.                 end;
  836.         end;
  837.     end;
  838.  
  839.  
  840.     procedure DoClear;
  841.         var
  842.             fwptr: WindowPtr;
  843.             kind: integer;
  844.     begin
  845.         fwptr := FrontWindow;
  846.         if fwptr = nil then
  847.             exit(DoClear);
  848.         kind := WindowPeek(fwptr)^.WindowKind;
  849.         if Kind = TextKind then begin
  850.                 DoTextClear;
  851.                 exit(DoClear);
  852.             end;
  853.         if not NoSelection then begin
  854.                 SetupUndo;
  855.                 WhatToUndo := UndoClear;
  856.                 CurrentOp := EraseOp;
  857.                 OpPending := true;
  858.                 RoiUpdateTime := 0;
  859.             end;
  860.     end;
  861.  
  862.  
  863.     procedure ShowClipboard;
  864.         var
  865.             width, height, hstart, vstart, i, NewScrapCount: integer;
  866.             okay:boolean;
  867.     begin
  868.         NewScrapCount := GetScrapCount;
  869.         if NewScrapCount <> OldScrapCount then begin
  870.                 WhatsOnClip := NothingOnClip;
  871.                 OldScrapCount := NewScrapCount;
  872.             end;
  873.         if WhatsOnClip = NothingOnClip then
  874.             ConvertFromSystemClipboard;
  875.         if (WhatsOnClip = RectPic) or (WhatsOnClip = NonRectPic) or (WhatsOnClip = ImportedPic) or (WhatsOnClip = CameraPic) then
  876.             with ClipBufinfo^.RoiRect do begin
  877.                     width := right - left;
  878.                     height := bottom - top;
  879.                     if NewPicWindow('Clipboard', width, height) then begin
  880.                             PastePicture;
  881.                             KillRoi;
  882.                             SetupUndo;
  883.                             info^.changes := false;
  884.                         end;
  885.                 end;
  886.         if WhatsOnClip = TextOnClip then begin
  887.             if MakeNewTextWindow('Clipboard', 400, 350) then
  888.                 DoTextPaste; 
  889.         end;
  890.     end;
  891.  
  892.  
  893.     function ScreenToPixmapH (hloc: integer): extended;
  894.     begin
  895.         with info^ do
  896.             ScreenToPixmapH := SrcRect.left + hloc / magnification;
  897.     end;
  898.  
  899.     function ScreenToPixmapV (vloc: integer): extended;
  900.     begin
  901.         with info^ do
  902.             ScreenToPixmapV := SrcRect.top + vloc / magnification;
  903.     end;
  904.  
  905.  
  906.     procedure DoSelection (obj: ObjectType; start, finish: point);
  907.         var
  908.             tRect: rect;
  909.             temp, StartH, StartV, FinishH, FinishV: integer;
  910.             TempRgn: RgnHandle;
  911.     begin
  912.         WhatToUndo := NothingToUndo;
  913.         Info^.RoiShowing := false;
  914.         RoiUpdateTime := 0;
  915.         if (start.h = finish.h) or (start.v = finish.v) then
  916.             exit(DoSelection);
  917.         if start.h > finish.h then begin
  918.                 temp := start.h;
  919.                 start.h := finish.h;
  920.                 finish.h := temp;
  921.             end;
  922.         if start.v > finish.v then begin
  923.                 temp := start.v;
  924.                 start.v := finish.v;
  925.                 finish.v := temp;
  926.             end;
  927.         StartH := round(ScreenToPixmapH(start.h));
  928.         StartV := round(ScreenToPixmapV(start.v));
  929.         FinishH := round(ScreenToPixmapH(finish.h));
  930.         FinishV := round(ScreenToPixmapV(finish.v));
  931.         SetRect(tRect, StartH, StartV, FinishH, FinishV);
  932.         with info^ do begin
  933.                 RoiShowing := true;
  934.                 if SelectionMode <> NewSelection then
  935.                     TempRgn := NewRgn;
  936.                 OpenRgn;
  937.                 case obj of
  938.                     SelectionOval:  begin
  939.                             FrameOval(tRect);
  940.                             roiType := OvalRoi;
  941.                         end;
  942.                     SelectionRect:  begin
  943.                             FrameRect(tRect);
  944.                             roiType := RectRoi;
  945.                         end;
  946.                 end;
  947.                 if SelectionMode = NewSelection then
  948.                     CloseRgn(roiRgn)
  949.                 else begin
  950.                         CloseRgn(TempRgn);
  951.                         if RgnNotTooBig(roiRgn, TempRgn) then begin
  952.                                 if SelectionMode = AddSelection then
  953.                                     UnionRgn(roiRgn, TempRgn, roiRgn)
  954.                                 else begin
  955.                                         DiffRgn(roiRgn, TempRgn, roiRgn);
  956.                                         UpdatePicWindow;
  957.                                     end;
  958.                             end;
  959.                         DisposeRgn(TempRgn);
  960.                         if GetHandleSize(handle(roiRgn)) = 10 then
  961.                             roiType := RectRoi
  962.                         else
  963.                             roiType := FreehandRoi;
  964.                         nCoordinates := 0;
  965.                     end;
  966.                 RoiRect := roiRgn^^.rgnBBox;
  967.             end;{with}
  968.         measuring := false;
  969.     end;
  970.  
  971.  
  972.     procedure DoObject; {(obj: ObjectType; event: EventRecord)}
  973.         var
  974.             Start, Finish, ScreenStart, ScreenFinish, osStart, osFinish: point;
  975.             r: rect;
  976.             DeltaX, DeltaY, switch: integer;
  977.             Constrain: boolean;
  978.             StartH, StartV: extended;
  979.     begin
  980.         SetPort(info^.wptr);
  981.         if obj = LineObj then
  982.             DrawLabels('DX:', 'DY:', 'Length:')
  983.         else
  984.             DrawLabels('Width:', 'Height:', '');
  985.         start := event.where;
  986.         StartH := ScreenToPixmapH(start.h);
  987.         StartV := ScreenToPixmapV(start.v);
  988.         osStart := start;
  989.         ScreenToOffscreen(osStart);
  990.         finish := start;
  991.         osFinish := finish;
  992.         ScreenToOffscreen(osFinish);
  993.         PenNormal;
  994.         PenMode(PatXor);
  995.         PenSize(1, 1);
  996.         while button do begin
  997.                 GetMouse(finish);
  998.                 with finish, Info^ do begin
  999.                         if h > wrect.right then
  1000.                             h := wrect.right;
  1001.                         if v > wrect.bottom then
  1002.                             v := wrect.bottom;
  1003.                         if h < 0 then
  1004.                             h := 0;
  1005.                         if v < 0 then
  1006.                             v := 0;
  1007.                     end;
  1008.                 if ShiftKeyDown then begin
  1009.                         DeltaX := finish.h - start.h;
  1010.                         DeltaY := finish.v - start.v;
  1011.                         if obj = lineObj then begin
  1012.                                 if abs(DeltaX) > abs(DeltaY) then
  1013.                                     finish.v := start.v
  1014.                                 else
  1015.                                     finish.h := start.h
  1016.                             end
  1017.                         else begin
  1018.                                 if ((DeltaX > 0) and (DeltaY < 0)) or ((DeltaX < 0) and (DeltaY > 0)) then
  1019.                                     switch := -1
  1020.                                 else
  1021.                                     switch := 1;
  1022.                                 if abs(DeltaX) > abs(DeltaY) then
  1023.                                     finish.h := start.h + switch * DeltaY
  1024.                                 else
  1025.                                     finish.v := start.v + switch * DeltaX;
  1026.                             end;
  1027.                     end;
  1028.                 osFinish := finish;
  1029.                 ScreenToOffscreen(osfinish);
  1030.                 case obj of
  1031.                     LineObj:  begin
  1032.                             MoveTo(start.h, start.v);
  1033.                             LineTo(finish.h, finish.v);
  1034.                             ShowDxDy(abs(ScreenToPixMapH(finish.h) - StartH), abs(ScreenToPixMapV(finish.v) - StartV));
  1035.                             MoveTo(start.h, start.v);
  1036.                             LineTo(finish.h, finish.v);
  1037.                         end;
  1038.                     Rectangle, SelectionRect:  begin
  1039.                             if obj = SelectionRect then begin
  1040.                                     PatIndex := (PatIndex + 1) mod 8;
  1041.                                     PenPat(AntPattern[PatIndex]);
  1042.                                 end;
  1043.                             Pt2Rect(start, finish, r);
  1044.                             FrameRect(r);
  1045.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  1046.                             Pt2Rect(start, finish, r);
  1047.                             FrameRect(r);
  1048.                         end;
  1049.                     SelectionOval:  begin
  1050.                             PatIndex := (PatIndex + 1) mod 8;
  1051.                             PenPat(AntPattern[PatIndex]);
  1052.                             Pt2Rect(start, finish, r);
  1053.                             FrameOval(r);
  1054.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  1055.                             Pt2Rect(start, finish, r);
  1056.                             FrameOval(r);
  1057.                         end;
  1058.                 end; {case}
  1059.             end;  {while button}
  1060.         if (obj = SelectionRect) or (obj = SelectionOval) then begin
  1061.                 DoSelection(obj, start, finish);
  1062.                 exit(DoObject);
  1063.             end;
  1064.         if (obj = LineObj) and ((CurrentTool = LineTool) or (CurrentTool = PlotTool)) then begin
  1065.                 MoveTo(start.h, start.v);
  1066.                 LineTo(finish.h, finish.v);
  1067.                 with info^ do begin
  1068.                         LX1 := StartH;
  1069.                         LY1 := StartV;
  1070.                         LX2 := ScreenToPixmapH(finish.h);
  1071.                         LY2 := ScreenToPixmapV(finish.v);
  1072.                         if LX1 > (PicRect.right - 1) then
  1073.                             LX1 := PicRect.right - 1;
  1074.                         if LY1 > (PicRect.bottom - 1) then
  1075.                             LY1 := PicRect.bottom - 1;
  1076.                         if LX1 < 0 then
  1077.                             LX1 := 0;
  1078.                         if LY1 < 0 then
  1079.                             LY1 := 0;
  1080.                         if LX2 > (PicRect.right - 1) then
  1081.                             LX2 := PicRect.right - 1;
  1082.                         if LY2 > (PicRect.bottom - 1) then
  1083.                             LY2 := PicRect.bottom - 1;
  1084.                         if LX2 < 0 then
  1085.                             LX2 := 0;
  1086.                         if LY2 < 0 then
  1087.                             LY2 := 0;
  1088.                     end;
  1089.                 exit(DoObject);
  1090.             end;
  1091.         DrawObject(obj, start, finish);
  1092.     end;
  1093.  
  1094.  
  1095.     procedure DrawSprayCan (xcenter, ycenter: integer);
  1096.         var
  1097.             i, xoffset, yoffset, nDots: LongInt;
  1098.     begin
  1099.         nDots := SprayCanDiameter div 4;
  1100.         if nDots < 15 then
  1101.             nDots := 15;
  1102.         for i := 1 to nDots do begin
  1103.                 repeat
  1104.                     xoffset := random mod SprayCanRadius;
  1105.                     yoffset := random mod SprayCanRadius;
  1106.                 until xoffset * xoffset + yoffset * yoffset <= SprayCanRadius2;
  1107.                 PutPixel(xcenter + xoffset, ycenter + yoffset, ForegroundIndex);
  1108.             end;
  1109.     end;
  1110.  
  1111.  
  1112.     procedure DoSprayCan;
  1113.   {Reference: "Spaying and Smudging", Dick Pountain, Byte, November 1987}
  1114.         var
  1115.             xcenter, ycenter, off: integer;
  1116.             MaskRect: rect;
  1117.             pt: point;
  1118.             SaveTicks:LongInt;
  1119.     begin
  1120.         info^.changes := true;
  1121.         off := SprayCanRadius;
  1122.         SaveTicks:=TickCount;
  1123.         repeat
  1124.             repeat until TickCount<>SaveTicks; {Update no more than 60 times per second}
  1125.             SaveTicks:=TickCount;
  1126.             GetMouse(pt);
  1127.             ScreenToOffscreen(pt);
  1128.             with MaskRect, pt do begin
  1129.                     left := h - off;
  1130.                     top := v - off;
  1131.                     right := h + off;
  1132.                     bottom := v + off;
  1133.                 end;
  1134.             with pt do begin
  1135.                     xcenter := h;
  1136.                     ycenter := v
  1137.                 end;
  1138.             DrawSprayCan(xcenter, ycenter);
  1139.             UpdateScreen(MaskRect);
  1140.         until not button;
  1141.         WhatToUndo := UndoEdit;
  1142.     end;
  1143.  
  1144.  
  1145.     procedure DoBrush; {(event: EventRecord)}
  1146.         var
  1147.             r, ScreenRect: rect;
  1148.             p1, p2, p2x, start: point;
  1149.             WhichWindow: WindowPtr;
  1150.             SaveLineWidth, SaveForegroundColor: integer;
  1151.             Constrained, MoreHorizontal, FirstTime: boolean;
  1152.             offset, width: integer;
  1153.             rWidth: double;
  1154.     begin
  1155.         SaveLineWidth := LineWidth;
  1156.         p1 := event.where;
  1157.         start := p1;
  1158.         if OptionKeyDown then begin
  1159.                 case CurrentTool of
  1160.                     Brush, Pencil: 
  1161.                         GetForegroundColor(event);
  1162.                     Eraser: 
  1163.                         GetBackgroundColor(event);
  1164.                 end;
  1165.                 if (CurrentTool = Brush) or (CurrentTool = Eraser) then
  1166.                     exit(DoBrush);
  1167.             end;
  1168.         case CurrentTool of
  1169.             Pencil: 
  1170.                 LineWidth := 1;
  1171.             Brush, Eraser:  begin
  1172.                     if CurrentTool = Brush then
  1173.                         width := BrushWidth
  1174.                     else
  1175.                         width := 16;
  1176.                     LineWidth := round(width / info^.magnification);
  1177.                     if LineWidth < 1 then
  1178.                         LineWidth := 1;
  1179.                 end;
  1180.         end;
  1181.         with info^ do
  1182.             rWidth := (LineWidth - 1) * info^.magnification / 2.0;
  1183.             offset := round(rWidth * 1.00000001);  {ppc-bug}
  1184.         if CurrentTool <> Pencil then
  1185.             with p1 do begin
  1186.                     h := h - offset;
  1187.                     v := v - offset
  1188.                 end;
  1189.         Constrained := ShiftKeyDown;
  1190.         FirstTime := true;
  1191.         if CurrentTool = eraser then begin
  1192.                 SaveForegroundColor := ForegroundIndex;
  1193.                 SetForegroundColor(BackgroundIndex)
  1194.             end;
  1195.         repeat
  1196.             GetMouse(p2);
  1197.             if CurrentTool <> Pencil then
  1198.                 with p2 do begin
  1199.                         h := h - offset;
  1200.                         v := v - offset
  1201.                     end;
  1202.             if FirstTime then
  1203.                 if not EqualPt(p1, p2) then begin
  1204.                         MoreHorizontal := abs(p2.h - p1.h) >= abs(p2.v - p1.v);
  1205.                         FirstTime := false;
  1206.                     end;
  1207.             if Constrained then
  1208.                 if MoreHorizontal then
  1209.                     p2.v := p1.v
  1210.                 else
  1211.                     p2.h := p1.h;
  1212.             if CurrentTool = brush then
  1213.                 DrawObject(BrushObj, p1, p2)
  1214.             else
  1215.                 DrawObject(LineObj, p1, p2);
  1216.             p1 := p2;
  1217.         until not button;
  1218.         if CurrentTool = Eraser then
  1219.             SetForegroundColor(SaveForegroundColor);
  1220.         LineWidth := SaveLineWidth;
  1221.         WhatToUndo := UndoEdit;
  1222.     end;
  1223.  
  1224.  
  1225.     procedure DrawCharacter; {(ch: char)}
  1226.         var
  1227.             str: str255;
  1228.     begin
  1229.         if Info = NoInfo then begin
  1230.                 beep;
  1231.                 exit(DrawCharacter)
  1232.             end;
  1233.         if ch = cr then
  1234.             with InsertionPoint do begin
  1235.                     h := TextStart.h;
  1236.                     v := v + CurrentSize;
  1237.                     SetupUndo;
  1238.                     TextStr := '';
  1239.                     TextStart := InsertionPoint;
  1240.                     exit(DrawCharacter)
  1241.                 end;
  1242.         if ch = BackSpace then
  1243.             with InsertionPoint do begin
  1244.                     if length(TextStr) > 0 then begin
  1245.                             delete(TextStr, length(TextStr), 1);
  1246.                             DisplayText(true);
  1247.                         end;
  1248.                     exit(DrawCharacter)
  1249.                 end;
  1250.         str := ' '; {Needed for MPW}
  1251.         str[1] := ch;
  1252.         TextStr := Concat(TextStr, str);
  1253.         DisplayText(true);
  1254.     end;
  1255.  
  1256.  
  1257.     procedure DoText; {(loc: point)}
  1258.   {Handles text tool mouse clicks.}
  1259.         var
  1260.             value: extended;
  1261.             str: str255;
  1262.             isValue: boolean;
  1263.     begin
  1264.         if NoUndo then
  1265.             exit(DoText);
  1266.         ScreenToOffscreen(loc);
  1267.         with loc do begin
  1268.                 InsertionPoint.h := h;
  1269.                 InsertionPoint.v := v + 4;
  1270.             end;
  1271.         IsInsertionPoint := true;
  1272.         TextStart := InsertionPoint;
  1273.         TextStr := '';
  1274.         if OptionKeyDown then
  1275.             with info^ do begin
  1276.                     isValue := true;
  1277.                     if (PreviousTool = LineTool) and (nLengths > 0) then
  1278.                         value := plength^[mCount2]
  1279.                     else if (PreviousTool = AngleTool) and (nAngles > 0) then
  1280.                         value := orientation^[mCount2]
  1281.                     else if mCount > 0 then
  1282.                         if AreaM in Measurements then
  1283.                             value := mArea^[mCount2]
  1284.                         else if MeanM in Measurements then
  1285.                             value := mean^[mCount2]
  1286.                         else
  1287.                             isValue := false;
  1288.                     if isValue then begin
  1289.                             RealToString(value, 1, precision, str);
  1290.                             if mCount2 > 0 then
  1291.                                 mCount2 := mCount2 - 1;
  1292.                             DrawTextString(str, TextStart, TextJust);
  1293.                         end;
  1294.                 end;
  1295.         WhatToUndo := UndoEdit;
  1296.     end;
  1297.  
  1298.  
  1299.     procedure DoFill (event: EventRecord);
  1300.         var
  1301.             loc: point;
  1302.             MaskBits: BitMap;
  1303.             BitMapSize: LongInt;
  1304.             tPort: GrafPtr;
  1305.             trect: rect;
  1306.             SaveGDevice: GDHandle;
  1307.     begin
  1308.         ShowWatch;
  1309.         loc := event.where;
  1310.         ScreenToOffscreen(loc);
  1311.         with info^ do begin
  1312.                 tRect := PicRect;
  1313.                 with tRect do
  1314.                     if (right mod 16 <> 0) and not Has32BitQuickDraw then
  1315.                         right := (right div 16) * 16 + 16;  {Workaround for SeedCFill bug that results in  garbage along right edge.}
  1316.                 with MaskBits do begin
  1317.                         RowBytes := PixelsPerLine div 8 + 1;
  1318.                         if odd(RowBytes) then
  1319.                             RowBytes := RowBytes + 1;
  1320.                         bounds := tRect;
  1321.                         BitMapSize := rowBytes * nLines;
  1322.                         baseAddr := NewPtr(BitMapSize);
  1323.                         if baseAddr = nil then begin
  1324.                                 beep;
  1325.                                 exit(DoFill)
  1326.                             end;
  1327.                     end;
  1328.                 SaveGDevice := GetGDevice;
  1329.                 SetGDevice(osGDevice);
  1330.                 GetPort(tPort);
  1331.                 SetPort(GrafPtr(osPort));
  1332.                 pmForeColor(ForegroundIndex);
  1333.                 SeedCFill(BitMapHandle(osPort^.PortPixMap)^^, MaskBits, tRect, tRect, loc.h, loc.v, nil, 0);
  1334.                 CopyBits(MaskBits, BitMapHandle(osPort^.PortPixMap)^^, tRect, tRect, SrcOr, nil);
  1335.                 DisposePtr(MaskBits.baseAddr);
  1336.                 changes := true;
  1337.             end; {with}
  1338.         SetPort(tPort);
  1339.         SetGDevice(SaveGDevice);
  1340.         UpdatePicWindow;
  1341.         WhatToUndo := UndoEdit;
  1342.     end;
  1343.  
  1344.  
  1345.     procedure SetSprayCanSize;
  1346.         var
  1347.             TempSize: integer;
  1348.             Canceled: boolean;
  1349.     begin
  1350.         TempSize := GetInt('Spray can diameter in pixels(2-250):', SprayCanDiameter, Canceled);
  1351.         if Canceled then
  1352.             exit(SetSprayCanSize);
  1353.         if (TempSize > 1) and (TempSize <= 250) then begin
  1354.                 SprayCanDiameter := TempSize;
  1355.                 SprayCanRadius := SprayCanDiameter div 2;
  1356.                 SprayCanRadius2 := SprayCanRadius * SprayCanRadius
  1357.             end
  1358.         else
  1359.             beep;
  1360.     end;
  1361.  
  1362.  
  1363.     procedure SetBrushSize;
  1364.         var
  1365.             TempSize: integer;
  1366.             Canceled: boolean;
  1367.             i, ticks, x, y: LongInt;
  1368.             v: integer;
  1369.     begin
  1370.         TempSize := GetInt('Brush Size in pixels(1..99):', BrushWidth, Canceled);
  1371.         if Canceled then
  1372.             exit(SetBrushSize);
  1373.         if (TempSize > 0) and (TempSize < 100) then begin
  1374.                 BrushWidth := TempSize;
  1375.                 BrushHeight := BrushWidth
  1376.             end
  1377.         else
  1378.             beep;
  1379. {exit(SetBrushSize);}
  1380.     {Timer}
  1381.         x := 100;
  1382.         y := 100;
  1383.         ticks := TickCount;
  1384.         for i := 1 to 1000000 do
  1385.             v := MyGetPixel(x, y);
  1386.         ShowMessage(concat('ticks=', long2str(TickCount - ticks)));
  1387.     end;
  1388.  
  1389.  
  1390.     procedure SetLineWidth;
  1391.         var
  1392.             TempSize: integer;
  1393.             Canceled: boolean;
  1394.     begin
  1395.         TempSize := GetInt('Line Width in pixels(1..100):', LineWidth, Canceled);
  1396.         if Canceled then
  1397.             exit(SetLineWidth);
  1398.         if (TempSize > 0) and (TempSize <= 100) then begin
  1399.                 LineWidth := TempSize;
  1400.                 ShowLineWidth;
  1401.             end
  1402.         else
  1403.             beep;
  1404.     end;
  1405.  
  1406.  
  1407.     procedure FindWhatToCopy;
  1408.         var
  1409.             kind: integer;
  1410.             WhichWindow: WindowPtr;
  1411.     begin
  1412.         WhatToCopy := NothingToCopy;
  1413.         WhichWindow := FrontWindow;
  1414.         if WhichWindow = nil then
  1415.             exit(FindWhatToCopy);
  1416.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1417.         if (CurrentTool = PickerTool) and (kind <> TextKind) then
  1418.             WhatToCopy := CopyColor
  1419.         else begin
  1420.                 if (kind = PicKind) and measuring and (not macro) then
  1421.                     kind := ResultsKind;
  1422.                 case kind of
  1423.                     PicKind: 
  1424.                         with info^, info^.RoiRect do
  1425.                             if RoiShowing and (left >= 0) and (top >= 0) and (right <= PicRect.right) and (bottom <= PicRect.bottom) then
  1426.                                 WhatToCopy := CopySelection;
  1427.                     HistoKind: 
  1428.                         WhatToCopy := CopyHistogram;
  1429.                     ProfilePlotKind: 
  1430.                         WhatToCopy := CopyPlot;
  1431.                     CalibrationPlotKind: 
  1432.                         WhatToCopy := CopyCalibrationPlot;
  1433.                     LUTKind: 
  1434.                         if info <> NoInfo then
  1435.                             WhatToCopy := CopyCLUT;
  1436.                     MapKind: 
  1437.                         if info <> NoInfo then
  1438.                             WhatToCopy := CopyGrayMap;
  1439.                     ToolKind: 
  1440.                         WhatToCopy := CopyTools;
  1441.                     TextKind:  begin
  1442.                             TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1443.                             if TextInfo <> nil then
  1444.                                 with TextInfo^.TextTE^^ do
  1445.                                     if selEnd > selStart then
  1446.                                         WhatToCopy := CopyText;
  1447.                         end;
  1448.                     InfoKind, ResultsKind: 
  1449.                         if mCount > 0 then
  1450.                             WhatToCopy := CopyMeasurements;
  1451.                     otherwise
  1452.                 end;
  1453.             end;
  1454.     end;
  1455.  
  1456.  
  1457.     procedure UpdateEditMenu;
  1458.         var
  1459.             DimUndo, ShowItems: boolean;
  1460.             str: str255;
  1461.             i: integer;
  1462.     begin
  1463.         with info^ do begin
  1464.                 if CurrentKind < 0 then begin   {DA is active, so activate Edit menu.}
  1465.                         SetMenuItemText(EditMenuH, UndoItem, 'Undo');
  1466.                         SetMenuItemText(EditMenuH, CutItem, 'Cut');
  1467.                         SetMenuItemText(EditMenuH, CopyItem, 'Copy');
  1468.                         SetMenuItem(EditMenuH, UndoItem, true);
  1469.                         for i := CutItem to ClearItem do
  1470.                             SetMenuItem(EditMenuH, i, true);
  1471.                         exit(UpdateEditMenu);
  1472.                     end;
  1473.                 if not (WhatToUndo in [UndoLUT, UndoMeasurement, UndoPoint]) and ((info = NoInfo) or (PixMapSize <> CurrentUndoSize)) then
  1474.                     WhatToUndo := NothingToUndo;
  1475.                 DimUndo := WhatToUndo = NothingToUndo;
  1476.                 SetMenuItem(EditMenuH, UndoItem, not DimUndo);
  1477.                 if DimUndo then
  1478.                     SetMenuItemText(EditMenuH, UndoItem, 'Undo');
  1479.                 case WhatToUndo of
  1480.                     UndoEdit: 
  1481.                         str := 'Editing';
  1482.                     UndoFlip: 
  1483.                         str := 'Flip';
  1484.                     UndoRotate: 
  1485.                         str := 'Rotate';
  1486.                     UndoFilter: 
  1487.                         str := 'Filtering';
  1488.                     UndoPaste: 
  1489.                         str := 'Paste';
  1490.                     UndoMeasurement, UndoPoint: 
  1491.                         str := 'Measurement';
  1492.                     UndoTransform: 
  1493.                         str := 'Transformation';
  1494.                     UndoClear: 
  1495.                         str := 'Clear';
  1496.                     UndoZoom: 
  1497.                         str := 'Zoom';
  1498.                     UndoOutline: 
  1499.                         str := 'Outline';
  1500.                     UndoSliceDelete, UndoFirstSliceDelete: 
  1501.                         str := 'Delete Slice';
  1502.                     UndoLUT: 
  1503.                         str := 'LUT Change';
  1504.                     otherwise
  1505.                         str := '';
  1506.                 end;
  1507.                 SetMenuItemText(EditMenuH, UndoItem, concat('Undo ', str));
  1508.                 FindWhatToCopy;
  1509.                 if WhatToCopy = CopySelection then
  1510.                     str := 'Cut Selection'
  1511.                 else
  1512.                     str := 'Cut';
  1513.                 SetMenuItemText(EditMenuH, CutItem, str);
  1514.                 SetMenuItem(EditMenuH, CutItem, (WhatToCopy = CopySelection) or (WhatToCopy = CopyText));
  1515.                 case WhatToCopy of
  1516.                     NothingToCopy, CopyText: 
  1517.                         str := '';
  1518.                     CopySelection: 
  1519.                         str := 'Selection';
  1520.                     CopyCLUT: 
  1521.                         str := 'LUT';
  1522.                     CopyGrayMap: 
  1523.                         str := 'Gray Map';
  1524.                     CopyTools: 
  1525.                         str := 'Tools';
  1526.                     CopyPlot: 
  1527.                         str := 'Plot';
  1528.                     CopyCalibrationPlot: 
  1529.                         str := 'Calibration Plot';
  1530.                     CopyHistogram: 
  1531.                         str := 'Histogram';
  1532.                     CopyMeasurements: 
  1533.                         str := 'Measurements';
  1534.                     CopyColor: 
  1535.                         str := 'Color';
  1536.                 end;
  1537.                 SetMenuItemText(EditMenuH, CopyItem, concat('Copy ', str));
  1538.                 SetMenuItem(EditMenuH, CopyItem, WhatToCopy <> NothingToCopy);
  1539.                 SetMenuItem(EditMenuH, ClearItem, (WhatToCopy = CopySelection) or (WhatToCopy = CopyText));
  1540.                 ShowItems := (WhatsOnClip <> NothingOnClip) or (OldScrapCount <> GetScrapCount);
  1541.                 SetMenuItem(EditMenuH, PasteItem, ShowItems);
  1542.                 SetMenuItem(EditMenuH, ShowClipboardItem, ShowItems);
  1543.                 ShowItems := info <> NoInfo;
  1544.                 if CurrentKind = TextKind then
  1545.                     SetMenuItemText(EditMenuH, FillItem, 'Find…')
  1546.                 else
  1547.                     SetMenuItemText(EditMenuH, FillItem, 'Fill');
  1548.                 SetMenuItem(EditMenuH, FillItem, ShowItems or (CurrentKind = TextKind));
  1549.                 SetMenuItem(EditMenuH, InvertItem, ShowItems);
  1550.                 SetMenuItem(EditMenuH, DrawBoundaryItem, ShowItems);
  1551.                 SetMenuItem(EditMenuH, DrawScaleItem, ShowItems);
  1552.                 if (RoiShowing and EqualRect(RoiRect, PicRect)) and (CurrentKind <> TextKind) then
  1553.                     SetMenuItemText(EditMenuH, SelectAllItem, 'Deselect All')
  1554.                 else
  1555.                     SetMenuItemText(EditMenuH, SelectAllItem, 'Select All');
  1556.                 SetMenuItem(EditMenuH, SelectAllItem, ShowItems or (CurrentKind = TextKind));
  1557.                 SetMenuItem(EditMenuH, DeselectItem, ShowItems and RoiShowing);
  1558.                 SetMenuItem(EditMenuH, ScaleAndRotateItem, ShowItems);
  1559.                 for i := RotateLeftItem to FlipHorizontalItem do
  1560.                     SetMenuItem(EditMenuH, i, ShowItems);
  1561.                 SetMenuItem(EditMenuH, UnZoomItem, ShowItems and ((magnification <> 1.0) or ScaleToFitWindow));
  1562.             end; {with}
  1563.     end;
  1564.  
  1565.  
  1566.     procedure ZoomOut;
  1567.         var
  1568.             Width, Height, divisor, NewWidth, NewHeight: integer;
  1569.             OldMagnification, xratio, yratio: extended;
  1570.     begin
  1571.         with Info^ do begin
  1572.                 if magnification < 2.0 then begin
  1573.                         beep;
  1574.                         exit(ZoomOut)
  1575.                     end;
  1576.                 OldMagnification := magnification;
  1577.                 if magnification = 2.0 then begin
  1578.                         magnification := 1.0;
  1579.                         divisor := 4
  1580.                     end
  1581.                 else if magnification = 3.0 then begin
  1582.                         magnification := 2.0;
  1583.                         divisor := 6
  1584.                     end
  1585.                 else if magnification = 4.0 then begin
  1586.                         magnification := 3.0;
  1587.                         divisor := 8
  1588.                     end
  1589.                 else begin
  1590.                         magnification := magnification / 2.0;
  1591.                         divisor := 4
  1592.                     end;
  1593.                 if EqualRect(SrcRect, PicRect) then begin {Make window smaller}
  1594.                         NewWidth := trunc(PicRect.right * magnification);
  1595.                         NewHeight := trunc(PicRect.bottom * magnification);
  1596.                         SizeWindow(wptr, NewWidth, NewHeight, true);
  1597.                         wrect.right := NewWidth;
  1598.                         wrect.bottom := NewHeight;
  1599.                         SrcRect := PicRect;
  1600.                         UpdateTitleBar;
  1601.                         UpdatePicWindow;
  1602.                         DrawMyGrowIcon(wptr);
  1603.                         exit(ZoomOut);
  1604.                     end;
  1605.                 if ((wrect.right > PicRect.right) or (wrect.bottom > PicRect.bottom)) then begin
  1606.                         xratio := wrect.right / PicRect.right;
  1607.                         yratio := wrect.bottom / PicRect.bottom;
  1608.                         if (xratio <> yratio) or ((xratio - trunc(xratio)) <> 0.0) then begin
  1609.                                 UnZoom;
  1610.                                 Exit(ZoomOut)
  1611.                             end;
  1612.                         SrcRect := PicRect;
  1613.                         Magnification := xratio;
  1614.                         UpdateTitleBar;
  1615.                         UpdatePicWindow;
  1616.                         DrawMyGrowIcon(wptr);
  1617.                         Exit(ZoomOut)
  1618.                     end;
  1619.             end; {with}
  1620.         with Info^.SrcRect, info^ do begin
  1621.                 if magnification = 1.0 then begin
  1622.                         width := wrect.right;
  1623.                         height := wrect.bottom;
  1624.                     end
  1625.                 else begin
  1626.                         width := round((right - left) * OldMagnification / Magnification);
  1627.                         height := round((bottom - top) * OldMagnification / Magnification);
  1628.                     end;
  1629.                 left := left - (width div divisor);
  1630.                 if left < 0 then
  1631.                     left := 0;
  1632.                 if (left + width) > Info^.PicRect.right then
  1633.                     left := Info^.PicRect.right - width;
  1634.                 top := top - (height div divisor);
  1635.                 if top < 0 then
  1636.                     top := 0;
  1637.                 if (top + height) > Info^.PicRect.bottom then
  1638.                     top := Info^.picRect.bottom - height;
  1639.                 right := left + width;
  1640.                 bottom := top + height;
  1641.                 RoiShowing := false;
  1642.                 UpdatePicWindow;
  1643.                 DrawMyGrowIcon(wptr);
  1644.                 UpdateTitleBar;
  1645.             end;
  1646.         ShowRoi;
  1647.     end;
  1648.  
  1649.  
  1650.     procedure DoGrow; {(WhichWindow: WindowPtr; event: EventRecord)}
  1651.         var
  1652.             NewSize: LongInt;
  1653.             trect, WinRect, SizeRect: rect;
  1654.             kind: integer;
  1655.             WasDigitizing: boolean;
  1656.             ZoomCenterH, ZoomCenterV, width, height: extended;
  1657.     begin
  1658.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1659.         if kind = PicKind then
  1660.             with info^, SizeRect do begin
  1661.                     if ScaleToFitWindow then
  1662.                         SizeRect := qd.ScreenBits.bounds
  1663.                     else begin
  1664.                             right := PicRect.right + 1;
  1665.                             bottom := PicRect.bottom + 1;
  1666.                             if magnification > 1.0 then begin
  1667.                                     right := round(right * magnification);
  1668.                                     bottom := round(bottom * magnification);
  1669.                                 end;
  1670.                             left := 32;
  1671.                             top := 32;
  1672.                             if left > right then
  1673.                                 left := right;
  1674.                             if top > bottom then
  1675.                                 top := bottom;
  1676.                         end
  1677.                 end
  1678.         else
  1679.             SetRect(SizeRect, 64, 48, 2048, 2048);
  1680.         NewSize := GrowWindow(WhichWindow, event.where, SizeRect);
  1681.         if newSize = 0 then
  1682.             exit(DoGrow);
  1683.         if kind = PicKind then
  1684.             with Info^ do begin
  1685.                     SetPort(wptr);
  1686.                     WasDigitizing := digitizing;
  1687.                     StopDigitizing;
  1688.                     InvalRect(wrect);
  1689.                     with trect do begin
  1690.                             top := 0;
  1691.                             left := 0;
  1692.                             right := LoWrd(NewSize);
  1693.                             bottom := HiWrd(NewSize);
  1694.                         end;
  1695.                     if ScaleToFitWindow then begin
  1696.                             ScaleImageWindow(trect);
  1697.                             wrect := trect;
  1698.                         end
  1699.                     else begin
  1700.                             if trect.right > PicRect.right * magnification then
  1701.                                 trect.right := trunc(PicRect.right * magnification);
  1702.                             if trect.bottom > PicRect.bottom * magnification then
  1703.                                 trect.bottom := trunc(PicRect.bottom * magnification);
  1704.                             wrect := trect;
  1705.                             with SrcRect do begin
  1706.                                     ZoomCenterH := left + (wrect.right / 2.0) / magnification;
  1707.                                     ZoomCenterV := top + (wrect.bottom / 2.0) / magnification;
  1708.                                     width := wrect.right / magnification;
  1709.                                     height := wrect.bottom / magnification;
  1710.                                     left := round(ZoomCenterH - width / 2.0);
  1711.                                     if left < 0 then
  1712.                                         left := 0;
  1713.                                     if (left + width) > PicRect.right then
  1714.                                         left := round(PicRect.right - width);
  1715.                                     top := round(ZoomCenterV - height / 2.0);
  1716.                                     if top < 0 then
  1717.                                         top := 0;
  1718.                                     if (top + height) > PicRect.bottom then
  1719.                                         top := round(picRect.bottom - height);
  1720.                                     right := round(left + width);
  1721.                                     bottom := round(top + height);
  1722.                                     wrect.right := trunc((right - left) * magnification);
  1723.                                     wrect.bottom := trunc((bottom - top) * magnification);
  1724.                                 end;
  1725.                             savewrect := wrect;
  1726.                         end;
  1727.                     SizeWindow(WhichWindow, wrect.right, wrect.bottom, true);
  1728.                     WindowState := NormalWindow;
  1729.                     if WasDigitizing then
  1730.                         StartDigitizing;
  1731.                     exit(DoGrow)
  1732.                 end; {with info^}
  1733.         if WhichWindow = PlotWindow then begin
  1734.                 PlotWidth := LoWrd(NewSize);
  1735.                 PlotHeight := HiWrd(NewSize);
  1736.                 SetPort(PlotWindow);
  1737.                 SizeWindow(PlotWindow, PlotWidth, Plotheight, true);
  1738.                 InvalRect(PlotWindow^.PortRect);
  1739.                 exit(DoGrow)
  1740.             end;
  1741.         if (kind = TextKind) then begin
  1742.                 TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1743.                 GrowTextWindow(NewSize);
  1744.                 exit(DoGrow)
  1745.             end;
  1746.         if WhichWindow = ResultsWindow then begin
  1747.                 ResultsWidth := LoWrd(NewSize);
  1748.                 ResultsHeight := HiWrd(NewSize);
  1749.                 SetPort(ResultsWindow);
  1750.                 with ResultsWindow^.PortRect do
  1751.                     SetRect(tRect, right - 12, bottom - 12, right, bottom);
  1752.                 EraseRect(trect); {Erase Grow Box}
  1753.                 SizeWindow(ResultsWindow, ResultsWidth, ResultsHeight, true);
  1754.                 MoveControl(hScrollBar, -1, ResultsHeight - ScrollBarWidth);
  1755.                 MoveControl(vScrollBar, ResultsWidth - ScrollBarWidth, -1);
  1756.                 SizeControl(hScrollBar, ResultsWidth - 13, ScrollBarWidth + 1);
  1757.                 SizeControl(vScrollBar, ScrollBarWidth + 1, ResultsHeight - 13);
  1758.                 InvalRect(ResultsWindow^.PortRect);
  1759.                 with ListTE^^.viewRect do begin
  1760.                         right := left + ResultsWidth - ScrollBarWidth - 4;
  1761.                         bottom := top + ResultsHeight - ScrollBarWidth;
  1762.                     end;
  1763.                 UpdateResultsScrollBars;
  1764.                 ScrollResultsText;
  1765.             end;
  1766.     end;
  1767.  
  1768.  
  1769.     procedure ZoomIn; {(event: EventRecord)}
  1770.         var
  1771.             width, height, OldMagnification: extended;
  1772.             PicCenterH, PicCenterV, NewWidth, NewHeight: integer;
  1773.             trect: rect;
  1774.     begin
  1775.         if Info = NoInfo then begin
  1776.                 beep;
  1777.                 exit(ZoomIn)
  1778.             end;
  1779.         if Info^.ScaleToFitWindow then begin
  1780.                 PutError('The magnifying glass does not work in "Scale to Fit Window" mode.');
  1781.                 exit(ZoomIn)
  1782.             end;
  1783.         if BitAnd(Event.modifiers, OptionKey) = OptionKey then begin
  1784.                 ZoomOut;
  1785.                 WhatToUndo := NothingToUndo;
  1786.                 exit(ZoomIn)
  1787.             end;
  1788.         with Info^ do begin
  1789.                 OldMagnification := magnification;
  1790.                 if magnification = 1.0 then
  1791.                     magnification := 2.0
  1792.                 else if magnification = 2.0 then
  1793.                     magnification := 3.0
  1794.                 else if magnification = 3.0 then
  1795.                     magnification := 4.0
  1796.                 else begin
  1797.                         magnification := magnification * 2.0;
  1798.                         if magnification > 64.0 then begin
  1799.                                 magnification := 64.0;
  1800.                                 exit(ZoomIn)
  1801.                             end;
  1802.                     end;
  1803.                 if (WindowState = NormalWindow) and EqualRect(SrcRect, PicRect) then {Make window bigger?}
  1804.                     with trect do begin
  1805.                             NewWidth := trunc(PicRect.right * magnification);
  1806.                             NewHeight := trunc(PicRect.bottom * magnification);
  1807.                             if NewWidth <= 640 then begin
  1808.                                     GetWindowRect(wptr, trect);
  1809.                                     if ((left + NewWidth) <= ScreenWidth) and ((top + NewHeight) <= ScreenHeight) then begin
  1810.                                             SizeWindow(wptr, NewWidth, NewHeight, true);
  1811.                                             wrect.right := NewWidth;
  1812.                                             wrect.bottom := NewHeight;
  1813.                                         end;
  1814.                                 end;
  1815.                         end;
  1816.             end; {with}
  1817.         with Info^.SrcRect, Info^ do begin
  1818.                 PicCenterH := left + round(event.where.h / OldMagnification);
  1819.                 PicCenterV := top + round(event.where.v / OldMagnification);
  1820.                 width := wrect.right / magnification;
  1821.                 height := wrect.bottom / magnification;
  1822.                 left := PicCenterH - round(width / 2.0);
  1823.                 if left < 0 then
  1824.                     left := 0;
  1825.                 if (left + width) > PicRect.right then
  1826.                     left := PicRect.right - round(width);
  1827.                 top := PicCenterV - round(height / 2.0);
  1828.                 if top < 0 then
  1829.                     top := 0;
  1830.                 if (top + height) > PicRect.bottom then
  1831.                     top := picRect.bottom - round(height);
  1832.                 right := left + round(width);
  1833.                 bottom := top + round(height);
  1834.                 wrect.right := trunc((right - left) * magnification);
  1835.                 wrect.bottom := trunc((bottom - top) * magnification);
  1836.                 SizeWindow(wptr, wrect.right, wrect.bottom, true);
  1837.                 RoiShowing := false;
  1838.                 UpdatePicWindow;
  1839.                 DrawMyGrowIcon(wptr);
  1840.                 UpdateTitleBar;
  1841.                 WhatToUndo := UndoZoom;
  1842.                 ShowRoi;
  1843.             end; {with}
  1844.     end;
  1845.  
  1846.  
  1847.     procedure SynchScroll;
  1848.         var
  1849.             n: integer;
  1850.             TempInfo, SaveInfo: InfoPtr;
  1851.     begin
  1852.         SaveInfo := info;
  1853.         if allsamesize then
  1854.             for n := 1 to nPics do begin
  1855.                     TempInfo := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1856.                     TempInfo^.SrcRect := info^.SrcRect;
  1857.                     TempInfo^.magnification := Info^.magnification;
  1858.                     info := TempInfo;
  1859.                     UpdatePicWindow;
  1860.                     Info := SaveInfo;
  1861.                 end
  1862.         else
  1863.             PutError('Synchronized scrolling requires all images and all windows to be the same size.');
  1864.     end;
  1865.  
  1866.  
  1867.     procedure Scroll; {(event: EventRecord)}
  1868.         var
  1869.             hstart, vstart, DeltaH, DeltaV, width, height: integer;
  1870.             loc: point;
  1871.             SaveSR: rect;
  1872.             WasDigitizing: boolean;
  1873.     begin
  1874.         with info^ do begin
  1875.                 if ScaleToFitWindow then begin
  1876.                         PutError('Scrolling does not work in "Scale to Fit Window" mode.');
  1877.                         exit(Scroll)
  1878.                     end;
  1879.                 WasDigitizing := digitizing;
  1880.                 StopDigitizing;
  1881.                 with event.where do begin
  1882.                         hstart := h;
  1883.                         vstart := v
  1884.                     end;
  1885.                 with SrcRect do begin
  1886.                         width := right - left;
  1887.                         height := bottom - top
  1888.                     end;
  1889.                 SaveSR := SrcRect;
  1890.                 while StillDown do begin
  1891.                         GetMouse(loc);
  1892.                         DeltaH := hstart - loc.h;
  1893.                         DeltaV := vstart - loc.v;
  1894.                         with SrcRect do begin
  1895.                                 left := SaveSR.left + DeltaH;
  1896.                                 if left < 0 then
  1897.                                     left := 0;
  1898.                                 if (left + width) > PicRect.right then
  1899.                                     left := PicRect.right - width;
  1900.                                 right := left + width;
  1901.                                 top := SaveSR.top + DeltaV;
  1902.                                 if top < 0 then
  1903.                                     top := 0;
  1904.                                 if (top + height) > PicRect.bottom then
  1905.                                     top := PicRect.bottom - height;
  1906.                                 bottom := top + height;
  1907.                             end;
  1908.                         UpdatePicWindow;
  1909.                         DrawMyGrowIcon(wptr);
  1910.                     end;
  1911.                 WhatToUndo := NothingToUndo;
  1912.                 ShowRoi;
  1913.                 if OptionKeyDown and (nPics > 1) then
  1914.                     SynchScroll;
  1915.                 if WasDigitizing then
  1916.                     StartDigitizing;
  1917.             end; {with info^}
  1918.     end;
  1919.  
  1920.  
  1921.     procedure ConverToSystemClipboard;
  1922.     {Converts local clipboard to system-wide clipboard}
  1923.     {when quitting or switching to other programs.}
  1924.     var
  1925.         PicH: PicHandle;
  1926.         err: LongInt;
  1927.         saveClipRgn: RgnHandle;
  1928.     begin
  1929.         PicH := nil;
  1930.         if ((WhatsOnClip = RectPic) or (WhatsOnClip = CameraPic)) and (ClipBuf <> nil) and not ClipboardConverted then
  1931.             with ClipBufInfo^ do begin
  1932.                 ShowWatch;
  1933.                 SetPort(GrafPtr(osPort));
  1934.                 saveClipRgn := NewRgn;
  1935.                 GetClip(saveClipRgn);
  1936.                 ClipRect(RoiRect);
  1937.                 LoadLUT(ctable);  {Switch to original LUT}
  1938.                 RGBForeColor(BlackRGB);
  1939.                 RGBBackColor(WhiteRGB);
  1940.                 PicH := OpenPicture(RoiRect);
  1941.                 with osPort^ do
  1942.                     CopyBits(BitMapHandle(portPixMap)^^, BitMapHandle(portPixMap)^^, RoiRect, RoiRect, SrcCopy, nil);
  1943.                 ClosePicture;
  1944.                 if info <> NoInfo then
  1945.                     LoadLUT(info^.ctable); {Restore LUT}
  1946.                 if (PicH <> nil) or ClipTextInBuffer then begin
  1947.                         err := ZeroScrap;
  1948.                         if err = NoErr then begin
  1949.                             if PicH <> nil then begin
  1950.                                 hlock(handle(PicH));
  1951.                                 err := PutScrap(GetHandleSize(handle(PicH)), 'PICT', handle(PicH)^);
  1952.                                 hunlock(handle(PicH));
  1953.                                 DisposeHandle(handle(PicH));
  1954.                             end;
  1955.                             if (err = noErr) and ClipTextInBuffer then
  1956.                                 err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  1957.                         end; {if err=NoErr}
  1958.                     end;
  1959.                 ClipboardConverted := true;
  1960.                 SetClip(saveClipRgn);
  1961.                 DisposeRgn(saveClipRgn);
  1962.             end; {with}
  1963.     end;
  1964.  
  1965.  
  1966.     procedure SetupOperation; {(item: integer)}
  1967.         var
  1968.             AutoSelectAll: boolean;
  1969.     begin
  1970.         if NotinBounds then
  1971.             exit(SetupOperation);
  1972.         if item = DrawBoundaryItem then
  1973.             if NoSelection then
  1974.                 exit(SetupOperation);
  1975.         if item = InvertItem then
  1976.             if not CheckCalibration then
  1977.                 exit(SetupOperation);
  1978.         StopDigitizing;
  1979.         AutoSelectAll := not Info^.RoiShowing;
  1980.         if AutoSelectAll then
  1981.             SelectAll(true);
  1982.         SetupUndo;
  1983.         WhatToUndo := UndoEdit;
  1984.         case Item of
  1985.             FillItem:  begin
  1986.                     CurrentOp := PaintOp;
  1987.                     OpPending := true
  1988.                 end;
  1989.             InvertItem:  begin
  1990.                     CurrentOp := InvertOp;
  1991.                     OpPending := true
  1992.                 end;
  1993.             DrawBoundaryItem:  begin
  1994.                     CurrentOp := FrameOp;
  1995.                     OpPending := true
  1996.                 end;
  1997.         end;
  1998.         if AutoSelectAll then
  1999.             KillRoi;
  2000.         RoiUpdateTime := 0; {Forces outline to be redrawn in scale-to-fit mode.}
  2001.     end;
  2002.  
  2003.  
  2004.     procedure DoUndo;
  2005.         var
  2006.             aok: boolean;
  2007.     begin
  2008.         case WhatToUndo of
  2009.             UndoMeasurement: 
  2010.                 UndoLastMeasurement(true);
  2011.             UndoPoint:  begin
  2012.                     Undo;
  2013.                     UpdatePicWindow;
  2014.                     UndoLastMeasurement(true);
  2015.                     WhatToUndo := NothingToUndo;
  2016.                 end;
  2017.             UndoZoom:  begin
  2018.                     ZoomOut;
  2019.                     if info^.magnification < 2 then
  2020.                         WhatToUndo := NothingToUndo;
  2021.                 end;
  2022.             UndoOutLine:  begin
  2023.                     undo;
  2024.                     if WandAutoMeasure then
  2025.                         UndoLastMeasurement(true);
  2026.                     WhatToUndo := NothingToUndo;
  2027.                     UpdatePicWindow;
  2028.                 end;
  2029.             UndoSliceDelete, UndoFirstSliceDelete: 
  2030.                 if info^.StackInfo <> nil then
  2031.                     with info^.StackInfo^ do begin
  2032.                             if WhatToUndo = UndoFirstSliceDelete then
  2033.                                 CurrentSlice := 0;
  2034.                             aok := AddSlice(false);
  2035.                             if aok then begin
  2036.                                     Undo;
  2037.                                     UpdatePicWindow;
  2038.                                 end
  2039.                             else if CurrentSlice = 0 then
  2040.                                 CurrentSlice := 1;
  2041.                         end;
  2042.             UndoLUT:  begin
  2043.                     UndoLutChange;
  2044.                     DrawMap;
  2045.                     DensitySlicing := false;
  2046.                 end;
  2047.             otherwise begin
  2048.                     if UndoFromClip then
  2049.                         OpPending := false;
  2050.                     if not OpPending then
  2051.                         undo;
  2052.                     WhatToUndo := NothingToUndo;
  2053.                     if IsInsertionPoint then begin
  2054.                             InsertionPoint := TextStart;
  2055.                             TextStr := '';
  2056.                         end;
  2057.                     UpdatePicWindow;
  2058.                     if OpPending and (CurrentOp = PasteOp) then begin
  2059.                             OpPending := false;
  2060.                             KillRoi;
  2061.                         end;
  2062.                     OpPending := false;
  2063.                 end;
  2064.         end; {case}
  2065.     end;
  2066.  
  2067.  
  2068.  
  2069. end.